package chargemanager

import (
	"bufio"
	"context"
	"encoding/binary"
	"fmt"
	"net"
	"sync"
	"time"

	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/log"
	"dev.ixmxm.top/rms/utils/tools"
)

type ChargerStatus uint8

const (
	ChargerWaitConnect           ChargerStatus = 0 //等待连接
	ChargerCommunicationOverTime ChargerStatus = 1 //充电通信超时
	ChargerOK                    ChargerStatus = 2 //充电桩正常
	ChargerError                 ChargerStatus = 3 //充电桩错误
)

//新充电桩初始化
func newCharger(info model.ChargeSite) *Charger {
	charger := &Charger{info: info, isStop: false}
	charger.operateLocker = new(sync.Mutex)
	go charger.init()
	return charger
}

type Charger struct {
	operateLocker *sync.Mutex        //操作锁
	connLocker    sync.Mutex         //连接锁
	conn          net.Conn           //sockert连接
	cancelFunc    context.CancelFunc //
	info          model.ChargeSite   //充电桩基本信息
	status        ChargerStatusWord  //充电桩状态数据
	isStop        bool               //
}

func (charger *Charger) GetOperateLocker() *sync.Mutex {
	return charger.operateLocker
}

//获取充电桩基本信息
func (charger Charger) GetInfo() model.ChargeSite {
	return charger.info
}

//获取充电桩状态
func (charger Charger) GetChargerStatus() ChargerStatus {
	if charger.conn == nil {
		return ChargerWaitConnect
	}
	if charger.status.expired() {
		return ChargerCommunicationOverTime
	}
	if charger.status.Code != ChargerOk {
		return ChargerError
	}
	return ChargerOK
}

//获取充电桩解析数据
func (charger Charger) GetStatusWord() ChargerStatusWord {
	// log.Warnf("获得充电状态：%+v", charger.status)
	return charger.status
}

//开始发送充电信号
func (charger *Charger) startCharge() codes.Code {
	t := time.NewTimer(30 * time.Second)
	defer t.Stop()
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-t.C:
			return codes.ErrStartChargeTimeout
		case <-ticker.C:
			switch {
			case charger.status.IsIn:
				signal := startChargeControlSignal(charger.info.Id).Bytes()
				log.Infof("发送开始充电信号:%X", signal)
				charger.write(signal)
			case charger.status.IsOuting:
			case charger.status.IsOut && charger.status.IsCharging:
				log.Infof("charger:%d start charge success", charger.info.Id)
				return nil
			}
		}
	}
}

//发送断电信号
func (charger *Charger) finishCharge() codes.Code {
	t := time.NewTimer(20 * time.Second)
	defer t.Stop()
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-t.C:
			return codes.ErrStartChargeTimeout
		case <-ticker.C:
			switch {
			case charger.status.IsIn:
				log.Infof("charger:%d finish charge success", charger.info.Id)
				return nil
			case charger.status.IsRetracting:
			case charger.status.IsOut || charger.status.IsCharging:
				signal := finishChargeControlSignal(charger.info.Id).Bytes()
				log.Infof("发送停止充电信号:%X", signal)
				charger.write(signal)
			}
		}
	}
}

//发送信号
func (charger *Charger) write(b []byte) {
	charger.connLocker.Lock()
	defer charger.connLocker.Unlock()
	if charger.conn == nil {
		return
	}
	charger.conn.Write(b)

}

//初始化
func (charger *Charger) init() {
	for {
		if charger.isStop {
			return
		}
		charger.connLocker.Lock()
		if charger.conn != nil {
			charger.conn.Close()
			charger.conn = nil
		}
		if charger.cancelFunc != nil {
			charger.cancelFunc()
			charger.cancelFunc = nil
		}
		address := fmt.Sprintf("%s:%d", charger.info.Ip, charger.info.Port)
		conn, err := net.Dial("tcp4", address)
		if err != nil {
			// log.Errorf("连接充电桩错误:%s", err.Error())
			charger.connLocker.Unlock()
			tools.Sleep(10.0)
			continue
		}
		if conn == nil {
			log.Error("连接充电桩对象为空！！！")
			charger.connLocker.Unlock()
			tools.Sleep(3.0)
			continue
		}
		charger.conn = conn
		ctx, cancel := context.WithCancel(context.Background())
		charger.cancelFunc = cancel
		charger.connLocker.Unlock()
		go charger.startRead(ctx)
		go charger.check(ctx)
		return
	}
}

//
func (charger *Charger) startRead(ctx context.Context) {
	scanner := bufio.NewScanner(charger.conn)
	scanner.Split(charger.status.splitFunc())
	for {
		select {
		case <-ctx.Done():
			if charger.conn != nil {
				charger.conn.Close()
			}
			return
		default:
			if scanner == nil {
				log.Errorf("读取充电桩数据错误 地址:%s port:%d", charger.info.Ip, charger.info.Port)
				return
			}
			//fmt.Printf("开始读取充电桩数据 地址:%s port:%d\n", charger.info.Ip, charger.info.Port)
			if scanner.Scan() {
				if charger.isStop {
					return
				}
				charger.status.Write(scanner.Bytes())
				charger.status.lastCommTime = time.Now()
			}
		}
	}
}

func (charger *Charger) check(ctx context.Context) {
	ticker := time.NewTicker(3 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			if charger.GetChargerStatus() == ChargerCommunicationOverTime {
				charger.init()
			}
		}
	}
}

var (
	frameHeader = [2]byte{0xA5, 0x5A}
	frameTail   = [2]byte{0x5A, 0xA5}
	lenHead     = binary.Size(frameHeader)
	totalLen    = 10
)
